package com.lry.util.jwt;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

import com.lry.util.LocalDateTimeUtils;

import io.jsonwebtoken.*;

/**
 *
 * @author SongDi
 * @date 2018/07/19
 */

public class JWTHelper {
    private static RsaKeyHelper rsaKeyHelper = new RsaKeyHelper();
    public static final String JWT_KEY_USER_ID = "userId";
    public static final String JWT_KEY_NAME = "userName";
    public static final String JWT_KEY_ACCOUNT = "account";
    public static final String JWT_KEY_TENANT_ID = "tenantId";
    public static final String JWT_KEY_GROUP_ID = "groupIdList";
    public static final String JWT_KEY_GROUP_NAME = "groupName";
    public static final String JWT_KEY_SUB_GROUP_ID = "subGroupIdList";
    public static final String JWT_KEY_ROLE_ID = "roleIdList";
    public static final String JWT_KEY_ADMIN = "isAdmin";
    public static final String JWT_KEY_PERMISSION_ID = "permissionIdList";

    /**
     * 密钥加密token
     *
     * @param sessionInfo
     * @param priKeyPath
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(SessionInfo sessionInfo, String priKeyPath, int expire) throws Exception {
        String compactJws =
            getJwtBuilder(sessionInfo).setExpiration(LocalDateTimeUtils.toDate(LocalDateTime.now().plusSeconds(expire)))
                .signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKeyPath)).compact();
        return compactJws;
    }

    /**
     * 密钥加密token
     *
     * @param sessionInfo
     * @param priKey
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(SessionInfo sessionInfo, byte priKey[], int expire) throws Exception {
        String compactJws = getJwtBuilder(sessionInfo)
            .setExpiration(LocalDateTimeUtils.toDate(LocalDateTime.now().plusSeconds(expire))).setIssuedAt(new Date())
            .signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKey)).compact();
        return compactJws;
    }

    /**
     * 密钥加密token
     *
     * @param sessionInfo
     * @param priKey
     * @param expire
     * @return
     * @throws Exception
     */
    public static String generateToken(SessionInfo sessionInfo, byte priKey[], int expire, Date iat) throws Exception {
        String compactJws =
            getJwtBuilder(sessionInfo).setExpiration(LocalDateTimeUtils.toDate(LocalDateTime.now().plusSeconds(expire)))
                .setIssuedAt(iat).signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKey)).compact();
        return compactJws;
    }

    private static JwtBuilder getJwtBuilder(SessionInfo sessionInfo) throws Exception {
        return Jwts.builder().setSubject(sessionInfo.getAccount())
                .claim(JWT_KEY_ADMIN,sessionInfo.getIsAdmin())
                .claim(JWT_KEY_USER_ID, sessionInfo.getUserId())
                .claim(JWT_KEY_NAME, sessionInfo.getUserName())
                .claim(JWT_KEY_ACCOUNT, sessionInfo.getAccount())
                .claim(JWT_KEY_GROUP_ID, sessionInfo.getGroupIdList())
                .claim(JWT_KEY_GROUP_NAME,sessionInfo.getGroupName())
                .claim(JWT_KEY_ROLE_ID, sessionInfo.getRoleIdList())
                .claim(JWT_KEY_PERMISSION_ID,sessionInfo.getPermissionIdList())
                .claim(JWT_KEY_SUB_GROUP_ID, sessionInfo.getSubGroupIdList());
    }

    /**
     * 公钥解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Jws<Claims> parserToken(String token, String pubKeyPath) throws Exception {
        Jws<Claims> claimsJws =
            Jwts.parser().setSigningKey(rsaKeyHelper.getPublicKey(pubKeyPath)).parseClaimsJws(token);
        return claimsJws;
    }

    /**
     * 公钥解析token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Jws<Claims> parserToken(String token, byte[] pubKey) throws Exception {

        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyHelper.getPublicKey(pubKey)).parseClaimsJws(token);
        return claimsJws;
    }

    /**
     * 获取token中的用户信息
     *
     * @param token
     * @param pubKeyPath
     * @return
     * @throws Exception
     */
    public static SessionInfo getInfoFromToken(String token, String pubKeyPath) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, pubKeyPath);
        Claims body = claimsJws.getBody();

        return getSessionInfo(body);
    }

    /**
     * 获取token中的用户信息
     *
     * @param token
     * @param pubKey
     * @return
     * @throws Exception
     */
    public static SessionInfo getInfoFromToken(String token, byte[] pubKey) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, pubKey);
        Claims body = claimsJws.getBody();
        return getSessionInfo(body);
    }

    private static SessionInfo getSessionInfo(Claims body) throws Exception {
        SessionInfo sessionInfo = new SessionInfo(getLongValue(body.get(JWT_KEY_USER_ID)),
            getObjectValue(body.get(JWT_KEY_NAME)), getLongValue(body.get(JWT_KEY_TENANT_ID)));
        sessionInfo.setIat(body.getIssuedAt().getTime() / 1000);
        sessionInfo.setGroupIdList((List<Integer>)body.get(JWT_KEY_GROUP_ID));
        sessionInfo.setRoleIdList((List<Integer>)body.get(JWT_KEY_ROLE_ID));
        sessionInfo.setSubGroupIdList((List<Integer>)body.get(JWT_KEY_SUB_GROUP_ID));
        sessionInfo.setAccount(getObjectValue(body.get(JWT_KEY_ACCOUNT)));
        return sessionInfo;
    }

    public static String getObjectValue(Object obj) {
        return obj == null ? "" : obj.toString();
    }

    public static Long getLongValue(Object obj) {
        return obj == null ? null : Long.valueOf(obj.toString());
    }
}
